package com.kent.hellokotlin.cClassAndObject

import android.support.v7.widget.RecyclerView
import android.view.View

//对象表达式与对象声明
/*有时候，我们需要创建一个对某个类做了轻微改动的类的对象，而不用为之显式声明新的子类。 Kotlin 用对象表达式和对象声明处理这种情况。*/

//对象表达式
/*要创建一个继承自某个（或某些）类型的匿名类的对象，我们会这么写：*/
private fun foo() {
    val rv: RecyclerView? = null
    rv?.setRecyclerListener(object : RecyclerView.RecyclerListener {
        override fun onViewRecycled(p0: RecyclerView.ViewHolder) {

        }

        override fun toString(): String {
            return super.toString() + ""
        }
    })


    val v: View? = null
    v?.setOnClickListener { TODO("Not yet implemented") }

}

/*如果超类型有一个构造函数，则必须传递适当的构造函数参数给它。 多个超类型可以由跟在冒号后面的逗号分隔的列表指定：*/
open class A4(i: Int) {}
interface B4 {}

val ab: A4 = object : A4(1), B4 {}

/*任何时候，如果我们只需要“一个对象而已”，并不需要特殊超类型，那么我们可以简单地写：*/
private fun foo1() {
    val justObj = object {
        val x = 1
        val y = 2
    }
    println("justObj x: ${justObj.x} , y: ${justObj.y}")
}

/*
请注意，匿名对象可以用作只在本地和私有作用域中声明的类型。如果你使用匿名对象作为公有函数的
返回类型或者用作公有属性的类型，那么该函数或属性的实际类型会是匿名对象声明的超类型，
如果你没有声明任何超类型，就会是 Any。在匿名对象中添加的成员将无法访问。
*/
class C4 {
    private fun foo() = object {
        val x: String = "private fun object"
    }

    fun publicFoo() = object {
        val x: String = "public fun object"
    }

    fun bar() {
        val x: String = foo().x
        //val publicFoo: Any = publicFoo().x
    }
}

//对象声明
/*单例模式在一些场景中很有用， 而 Kotlin（继 Scala 之后）使单例声明变得很容易：*/
object SingletonObject {
    val listeners = mutableListOf<RecyclerView.OnScrollListener>()
    fun addListener(listener: RecyclerView.OnScrollListener) {
        listeners.add(listener)
    }

    fun removeListener(listener: RecyclerView.OnScrollListener) {
        listeners.remove(listener)
    }
}

private fun foo2() {
    val listener = object : RecyclerView.OnScrollListener() {}
    SingletonObject.addListener(listener)
    SingletonObject.removeListener(listener)
}

//伴生对象
class MyClass1 {
    /*类内部的对象声明可以用 companion 关键字标记：*/
    companion object Factory {
        fun create() = MyClass1()
    }
}

class MyClass2 {
    /*该伴生对象的成员可通过只使用类名作为限定符来调用：*/
    companion object {
        fun create() = MyClass2()
    }
}

/*请注意，即使伴生对象的成员看起来像其他语言的静态成员，在运行时他们仍然是真实对象的实例成员，而且，例如还可以实现接口：*/
interface Factory<T>{
    fun create():T
}

class MyClass3 {
    companion object :Factory<MyClass3>{
        override fun create(): MyClass3 {
            return MyClass3()
        }
    }
}


private fun foo3() {
    MyClass1.Factory.create()
    MyClass1.create()
    MyClass2.Companion.create()
    MyClass2.create()

    val myClass3: Factory<MyClass3> = MyClass3
}

fun main() {
    foo()
    foo1()
}